home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #2 / Ham Radio 2000 - Volume 2.iso / HAMV2 / TCP_IP / TNOS230S / DRSI.C < prev    next >
C/C++ Source or Header  |  1996-12-28  |  32KB  |  1,118 lines

  1. #ifdef MSDOS
  2. /*
  3.  * Version with Stopwatches
  4.  *
  5.  * 0 - Not used
  6.  * 1 - rx_fsm run time
  7.  * 2 - drtx_active run time (per character tx time)
  8.  * 
  9.  * Interface driver for the DRSI board for KA9Q's TCP/IP on an IBM-PC ONLY!
  10.  *
  11.  * Derived from a driver written by Art Goldman, WA3CVG
  12.  * (c) Copyright 1987 All Rights Reserved
  13.  * Permission for non-commercial use is hereby granted provided this notice
  14.  * is retained.  For info call: (301) 997-3838.
  15.  *
  16.  * Heavily re-written from the original,  a driver for the EAGLE board into
  17.  * a driver for the DRSI PC* Packet adpator. Copyright as original, all
  18.  * amendments likewise providing credit given and notice retained.
  19.  * Stu Phillips - N6TTO, W6/G8HQA (yes Virginia,  really !).
  20.  * For info call: (408) 285-4142
  21.  *
  22.  * This driver supports 1 (one) DRSI board.
  23.  * 
  24.  * Reformatted and added ANSI-style declarations, integrated into NOS
  25.  * by KA9Q, 10/14/89
  26.  *
  27.  * Latest set of defect fixes added 1/2/90 by N6TTO
  28.  * 1. Made P-PERSIST work properly
  29.  * 2. Fixed UNDERRUN bug when in DEFER state
  30.  * 3. Tx now defers correctly when DCD is high (!)
  31.  *
  32.  * Changed 3/4/90 by N6TTO
  33.  * Changed method of enabling the IRQ to the 8259 to call maskon()
  34.  * instead of clrbit(); change made to allow interrupts > 8 to work
  35.  * on an AT.
  36.  *
  37.  * Changed 11/14/90 by N6TTO
  38.  * Fixed incompatiblity between current NOS memory allocation scheme
  39.  * and changes made to speed up drsi transmit state machine.
  40.  *
  41.  */
  42.  
  43. #include "global.h"
  44. #ifdef DRSI
  45. #include <dos.h>
  46. #include <time.h>
  47. #include "mbuf.h"
  48. #include "iface.h"
  49. #include "pktdrvr.h"
  50. #include "netuser.h"
  51. #include "drsi.h"
  52. #include "ax25.h"
  53. #include "trace.h"
  54. #include "pc.h"
  55. #include "z8530.h"
  56. #include "devparam.h"
  57.  
  58. #if !defined(_lint)
  59. static char rcsid[] OPTIONAL = "$Id: drsi.c,v 1.12 1996/12/29 02:47:22 root Exp root $";
  60. #endif
  61.  
  62. static int32 dr_ctl (struct iface *iface,int cmd,int set,int32 val);
  63. static int dr_raw (struct iface *iface,struct mbuf *bp);
  64. static int dr_stop (struct iface *iface);
  65. static void dr_wake (struct drchan *hp,int rx_or_tx,
  66.     void (*routine(struct drchan *),int ticks));
  67. static int drchanparam (struct drchan *hp);
  68. static void drexint (struct drchan *hp);
  69. static void drinitctc (unsigned port);
  70. static void drrx_active (struct drchan *hp);
  71. static void drrx_enable (struct drchan *hp);
  72. static void drtx_active (struct drchan *hp);
  73. static void drtx_defer (struct drchan *hp);
  74. static void drtx_downtx (struct drchan *hp);
  75. static void drtx_flagout (struct drchan *hp);
  76. static void drtx_idle (struct drchan *hp);
  77. static void drtx_rrts (struct drchan *hp);
  78. static void drtx_tfirst (struct drchan *hp);
  79. static char read_ctc (unsigned port,unsigned reg);
  80. static void rx_fsm (struct drchan *hp);
  81. static void tx_fsm (struct drchan *hp);
  82. static void write_ctc (unsigned port,unsigned reg,unsigned val);
  83.  
  84. struct DRTAB Drsi[DRMAX];    /* Device table - one entry per card */
  85. void (*Drhandle[]) (void) = { dr0vec };  /* handler interrupt vector table */
  86. struct drchan Drchan[2*DRMAX];     /* channel table - 2 entries per card */
  87. int16 Drnbr;
  88.  
  89. /* Set specified routine to be 'woken' up after specified number
  90.  * of ticks (allows CPU to be freed up and reminders posted);
  91.  */
  92. static void
  93. dr_wake(hp, rx_or_tx, routine, ticks)
  94. struct drchan *hp;
  95. int rx_or_tx;
  96. void (*routine) (struct drchan *);
  97. int ticks;
  98. {
  99.     hp->w[rx_or_tx].wcall = routine;
  100.     hp->w[rx_or_tx].wakecnt = ticks;
  101. }
  102.  
  103. /* Master interrupt handler.  One interrupt at a time is handled.
  104.  * here. Service routines are called from here.
  105.  */
  106. void
  107. drint(dev)
  108. int dev;
  109. {
  110.     register char st;
  111.     register int16 pcbase, i;
  112.     struct drchan *hpa,*hpb;
  113.  
  114.     Drsi[dev].ints++;
  115.     pcbase = Drsi[dev].addr;
  116.     hpa = &Drchan[2 * dev];
  117.     hpb = &Drchan[(2 * dev)+1];
  118.  
  119. yuk:
  120.     /* Check CTC for timer interrupt */
  121.     st = read_ctc(pcbase, Z8536_CSR3);
  122.     if(st & Z_IP){
  123.         /* Reset interrupt pending */
  124.         write_ctc(pcbase, Z8536_CSR3, Z_CIP|Z_GCB);
  125.         for(i=0;i<=1;i++){
  126.             if(hpa->w[i].wakecnt){
  127.                 if(--hpa->w[i].wakecnt == 0){
  128.                     (hpa->w[i].wcall)(hpa);
  129.                 }
  130.             }
  131.             if(hpb->w[i].wakecnt){
  132.                 if(--hpb->w[i].wakecnt == 0){
  133.                     (hpb->w[i].wcall)(hpb);
  134.                 }
  135.             }
  136.         }
  137.     }
  138.     /* Check the SIO for interrupts */
  139.  
  140.     /* Read interrupt status register from channel A */
  141.     while((st = read_scc(pcbase+CHANA+CTL,R3)) != 0){
  142.         /* Use IFs to process ALL interrupts pending
  143.          * because we need to check all interrupt conditions
  144.          */
  145.         if(st & CHARxIP){
  146.             /* Channel A Rcv Interrupt Pending */
  147.             rx_fsm(hpa);
  148.         }
  149.         if(st & CHBRxIP){
  150.             /* Channel B Rcv Interrupt Pending */
  151.             rx_fsm(hpb);
  152.         }
  153.         if(st & CHATxIP){
  154.             /* Channel A Transmit Int Pending */
  155.             tx_fsm(hpa);
  156.         }
  157.         if(st & CHBTxIP){
  158.             /* Channel B Transmit Int Pending */
  159.             tx_fsm(hpb);
  160.         }
  161.         if(st & CHAEXT){
  162.             /* Channel A External Status Int */
  163.             drexint(hpa);
  164.         }
  165.         if(st & CHBEXT){
  166.             /* Channel B External Status Int */
  167.             drexint(hpb);
  168.         }
  169.         /* Reset highest interrupt under service */
  170.         write_scc(hpa->base+CTL,R0,RES_H_IUS);
  171.  
  172.     } /* End of while loop on int processing */
  173.     if(read_ctc(pcbase, Z8536_CSR3) & Z_IP)
  174.         goto yuk;
  175. }
  176.  
  177.  
  178. /* DRSI SIO External/Status interrupts
  179.  * This can be caused by a receiver abort, or a Tx UNDERRUN/EOM.
  180.  * Receiver automatically goes to Hunt on an abort.
  181.  *
  182.  * If the Tx Underrun interrupt hits, change state and
  183.  * issue a reset command for it, and return.
  184.  */
  185. static void
  186. drexint(hp)
  187. register struct drchan *hp;
  188. {
  189.     register int base = hp->base;
  190.     char st, i_state;
  191.  
  192.     i_state = disable ();     /* disable interrupts */
  193.     hp->exints++;
  194.  
  195.     st = read_scc(base+CTL,R0);     /* Fetch status */
  196.  
  197.     /* Check for Tx UNDERRUN/EOM - only in Transmit Mode */
  198.         /* Note that the TxEOM bit remains set once we go    */
  199.     /* back to receive.  The following qualifications    */
  200.     /* are necessary to prevent an aborted frame causing */
  201.     /* a queued transmit frame to be tossed when in      */
  202.     /* DEFER state on transmit.                 */
  203.     if((hp->tstate != DEFER) && (hp->rstate==0) && (st & TxEOM)){
  204.         if(hp->tstate != UNDERRUN){
  205.             /* This is an unexpected underrun.  Discard the current
  206.              * frame (there's no way to rewind),  kill the transmitter
  207.              * and return to receive with a wakeup posted to get the
  208.              * next (if any) frame.  Any recovery will have to be done
  209.              * by higher level protocols (yuk).
  210.              */
  211.             write_scc(base, R5, Tx8|DTR);    /* Tx off now */
  212.             write_scc(base, R1, 0);        /* Prevent ext.status int */
  213.             write_scc(base, R0, RES_Tx_P);  /* Reset Tx int pending */
  214.             write_scc(base, R0, ERR_RES);
  215.             write_scc(base, R0, RES_EOM_L); /* Reset underrun latch */
  216.             free_p(hp->sndbuf);
  217.             hp->tstate = IDLE;
  218.             hp->tx_state = drtx_idle;
  219.             dr_wake(hp, TX, tx_fsm, hp->slotime);
  220.             hp->rstate = ENABLE;
  221.             hp->rx_state = drrx_enable;
  222.             drrx_enable(hp);
  223.         }
  224.     }
  225.     /* Receive Mode only
  226.      * This triggers when hunt mode is entered, & since an ABORT
  227.      * automatically enters hunt mode, we use that to clean up
  228.      * any waiting garbage
  229.      */
  230.     if((hp->rstate != IDLE) && (st & BRK_ABRT)){
  231.         if(hp->rcvbuf != NULLBUF){
  232.             hp->rcp = hp->rcvbuf->data;
  233.             hp->rcvbuf->cnt = 0;
  234.         }
  235.         while(read_scc(base,R0) & Rx_CH_AV)
  236.             (void) inportb(base+DATA);
  237.         hp->aborts++;
  238.         hp->rstate = ACTIVE;
  239.         write_scc(base, R0, ERR_RES);
  240.     }
  241.     /* reset external status latch */
  242.     write_scc(base,R0,RES_EXT_INT);
  243.     restore(i_state);
  244. }
  245.  
  246. /* Receive Finite State Machine - dispatcher */
  247. static void
  248. rx_fsm(hp)
  249. struct drchan *hp;
  250. {
  251.     char i_state = disable ();
  252.  
  253.     hp->rxints++;
  254.     (*hp->rx_state)(hp);
  255.     restore(i_state);
  256. }
  257.  
  258. /* drrx_enable
  259.  * Receive ENABLE state processor
  260.  */
  261. static void
  262. drrx_enable(hp)
  263. struct drchan *hp;
  264. {
  265.     register int16 base = hp->base;
  266.  
  267.     write_scc(base, R1, INT_ALL_Rx|EXT_INT_ENAB);
  268.     write_scc(base, R15, BRKIE);    /* Allow ABORT Int */
  269.     write_scc(base, R14, BRSRC|BRENABL|SEARCH);
  270.     /* Turn on rx and enter hunt mode */
  271.     write_scc(base, R3, ENT_HM|RxENABLE|RxCRC_ENAB|Rx8);
  272.  
  273.     if(hp->rcvbuf != NULLBUF){
  274.         hp->rcvbuf->cnt = 0;
  275.         hp->rcp = hp->rcvbuf->data;
  276.     }
  277.     hp->rstate = ACTIVE;
  278.     hp->rx_state = drrx_active;
  279. }
  280.  
  281. /* drrx_active
  282.  * Receive ACTIVE state processor
  283.  */
  284. static void
  285. drrx_active(hp)
  286. struct drchan *hp;
  287. {
  288.     register int16 base = hp->base;
  289.     unsigned char rse,st;
  290.     struct phdr *phdr;
  291.     struct mbuf *bp;
  292.  
  293.     /* Allocate a receive buffer if not already present */
  294.     if(hp->rcvbuf == NULLBUF){
  295.         bp = hp->rcvbuf = alloc_mbuf(hp->bufsiz);
  296.         if(bp == NULLBUF){
  297.             /* No buffer - abort the receiver */
  298.             write_scc(base, R3, ENT_HM|RxENABLE|RxCRC_ENAB|Rx8);
  299.             /* Clear character from rx buffer in SIO */
  300.             (void) inportb(base+DATA);
  301.             return;
  302.         }
  303.         hp->rcvbuf->cnt = 0; 
  304.         hp->rcp = hp->rcvbuf->data;
  305.     }
  306.  
  307.     st = read_scc(base, R0); /* get interrupt status from R0 */
  308.     rse = read_scc(base,R1); /* get special status from R1 */
  309.  
  310.     if(st & Rx_CH_AV){
  311.         /* there is a char to be stored
  312.          * read special condition bits before reading the data char
  313.          * (already read above)
  314.          */
  315.         if(rse & Rx_OVR){
  316.             /* Rx overrun - toss buffer */
  317.             hp->rcp = hp->rcvbuf->data;    /* reset buffer pointers */
  318.             hp->rcvbuf->cnt = 0;
  319.             hp->rstate = RXERROR;    /* set error flag */
  320.             hp->rovers++;        /* count overruns */
  321.         } else if(hp->rcvbuf->cnt >= hp->bufsiz){
  322.             /* Too large -- toss buffer */
  323.             hp->toobig++;
  324.             hp->rcp = hp->rcvbuf->data;    /* reset buffer pointers */
  325.             hp->rcvbuf->cnt = 0;
  326.             hp->rstate = TOOBIG;    /* when set, chars are not stored */
  327.         }
  328.         /* ok, we can store the received character now */
  329.         if((hp->rstate == ACTIVE) && ((st & BRK_ABRT) == 0)){
  330.             *hp->rcp++ = inportb(base+DATA); /* char to rcv buff */
  331.             hp->rcvbuf->cnt++;         /* bump count */
  332.         } else {
  333.             /* got to empty FIFO */
  334.             (void) inportb(base+DATA);
  335.             hp->rcp = hp->rcvbuf->data;    /* reset buffer pointers */
  336.             hp->rcvbuf->cnt = 0;
  337.             hp->rstate = RXABORT;
  338.             write_scc(base,R0,ERR_RES);    /* reset err latch */
  339.         }
  340.     }
  341.     /* The End of Frame bit is ALWAYS associated with a character,
  342.      * usually, it is the last CRC char.  Only when EOF is true can
  343.      * we look at the CRC byte to see if we have a valid frame
  344.      */
  345.     if(rse & END_FR){
  346.         hp->rxframes++;
  347.         /* END OF FRAME -- Make sure Rx was active */
  348.         if(hp->rcvbuf->cnt > 0){    /* any data to store */
  349.             /* looks like a frame was received
  350.              * now is the only time we can check for CRC error
  351.              */
  352.             if((rse & CRC_ERR) || (hp->rstate > ACTIVE) ||
  353.              (hp->rcvbuf->cnt < 10) || (st & BRK_ABRT)){
  354.                 /* error occurred; toss frame */
  355.                 if(rse & CRC_ERR)
  356.                     hp->crcerr++;    /* count CRC errs */
  357.                 hp->rcp = hp->rcvbuf->data;
  358.                 hp->rcvbuf->cnt = 0;
  359.                 hp->rstate = ACTIVE;   /* Clear error state */
  360.             } else {
  361.                 /* Here we have a valid frame */
  362.                 bp = alloc_mbuf(sizeof(struct phdr));
  363.                 bp->cnt = sizeof(struct phdr);
  364.                 phdr = (struct phdr *)bp->data;
  365.                 phdr->type = CL_AX25;
  366.                 phdr->iface = hp->iface;
  367.                 bp->next = hp->rcvbuf;
  368.                 hp->rcvbuf->cnt -= 2;    /* chuck FCS bytes */
  369.                 enqueue(&Hopper, bp);    /* queue it in */
  370.                 hp->enqueued++;
  371.                 /* packet queued - reset buffer pointer */
  372.                 hp->rcvbuf = NULLBUF;
  373.             } /* end good frame queued */
  374.         }  /* end check for active receive upon EOF */
  375.     }
  376. }
  377.  
  378. /*
  379.  * TX finite state machine - dispatcher
  380.  */
  381. static void
  382. tx_fsm(hp)
  383. struct drchan *hp;
  384. {
  385.     char i_state = disable ();
  386.     if(hp->tstate != DEFER && hp->tstate)
  387.         hp->txints++;
  388.     (*hp->tx_state)(hp);
  389.     restore(i_state);
  390. }
  391.  
  392. /* drtx_idle
  393.  * Transmit IDLE transmit state processor
  394.  */
  395. static void
  396. drtx_idle(hp)
  397. struct drchan *hp;
  398. {
  399.     register int16 base;
  400.  
  401.     /* Tx idle - is there a frame to transmit ? */
  402.     if((hp->sndbuf = dequeue(&hp->sndq)) == NULLBUF){
  403.         /* Nothing to send - return to receive mode
  404.          * Turn Tx off - any trailing flag should have been sent
  405.          * by now
  406.          */
  407. #ifdef DRSIDEBUG
  408.         printf("Nothing to TX\n");
  409. #endif
  410.         base = hp->base;
  411.         write_scc(base, R5, Tx8|DTR);   /* Tx off now */
  412.         write_scc(base, R0, ERR_RES);    /* Reset error bits */
  413.  
  414.         /* Delay for squelch tail before enabling receiver */
  415.         hp->rstate = ENABLE;
  416.         hp->rx_state = drrx_enable;
  417.         dr_wake(hp, RX, rx_fsm, hp->squeldelay);
  418.     } else {
  419.         /* Frame to transmit */
  420.         hp->tstate = DEFER;
  421.         hp->tx_state = drtx_defer;
  422.         drtx_defer(hp);
  423.     }
  424. }
  425.  
  426. /* drtx_defer
  427.  * Transmit DEFER state processor
  428.  */
  429. static void
  430. drtx_defer(hp)
  431. struct drchan *hp;
  432. {
  433.     register int16 base = hp->base;
  434.  
  435.     /* We may have defered a previous tx attempt - in any event...
  436.      * Check DCD in case someone is already transmitting
  437.      * then check to see if we should defer due to P-PERSIST.
  438.      */
  439.  
  440. #ifdef DRSIDEBUG
  441.     printf("drtx_defer - checking for DCD\n");
  442. #endif
  443.     if((read_scc(base+CTL, R0) & DCD) > 0){
  444.         /* Carrier detected - defer */
  445.         hp->txdefers++;
  446.         dr_wake(hp, TX, tx_fsm, 10);    /* Defer for 100 mS */
  447. #ifdef DRSIDEBUG
  448.         printf("drtx_defer - TX deferred\n");
  449. #endif
  450.         return;
  451.     }
  452.  
  453. #ifdef DRSIDEBUG
  454.     printf("drtx_defer - checking for P-PERSIST backoff\n");
  455. #endif
  456.     /* P-PERSIST is checked against channel 3 of the 8536 which is
  457.      * the free running counter for the 10 mS tick; The counter
  458.      * goes through 0x6000 ticks per 10 mS or one tick every
  459.      * 407 nS - this is pretty random compared to the DOS time of
  460.      * day clock (0x40:0x6C) used by the other (EAGLE) drivers.
  461.      */
  462.         if (hp->persist <= read_ctc(base,Z8536_CC3LSB)) {
  463. #ifdef DRSIDEBUG
  464.         printf("drtx_defer - BACKOFF\n");
  465. #endif
  466.         hp->txppersist++;
  467.         dr_wake (hp, TX, tx_fsm, hp->slotime);
  468.         return;
  469.     }
  470.     /* No backoff - set RTS and start to transmit frame */
  471.     write_scc(base, R1, 0);        /* Prevent external status int */
  472.     write_scc(base, R3, Rx8);    /* Turn Rx off */
  473.     hp->rstate = IDLE;        /* Mark Rx as idle */
  474.     hp->tstate = RRTS;
  475.     hp->tx_state = drtx_rrts;
  476. #ifdef DRSIDEBUG
  477.     printf("drtx_defer - wake posted for drtx_rrts\n");
  478. #endif
  479.     write_scc(base, R9, 0);        /* Interrupts off */
  480.     write_scc(base,R5,RTS|Tx8|DTR);    /* Turn tx on */
  481.     dr_wake(hp, TX, tx_fsm, 10);
  482. }
  483.  
  484. /* drtx_rrts
  485.  * Transmit RRTS state processor
  486.  */
  487. static void
  488. drtx_rrts(hp)
  489. struct drchan *hp;
  490. {
  491.     register int16 base = hp->base;
  492.  
  493.     write_scc(base, R9, 0);    /* Interrupts off */
  494.     write_scc(base,R5,TxCRC_ENAB|RTS|TxENAB|Tx8|DTR);    /* Tx now on */
  495.     hp->tstate = TFIRST;
  496.     hp->tx_state = drtx_tfirst;
  497. #ifdef DRSIDEBUG
  498.     printf("8530 Int status %x\n", read_scc(base+CHANA,R3) & 0xff); 
  499.     printf("drtx_rrts - Wake posted for TXDELAY\n");
  500. #endif
  501.     dr_wake(hp, TX, tx_fsm, hp->txdelay);
  502. }
  503.     
  504. /* drtx_tfirst
  505.  * Transmit TFIRST state processor
  506.  */
  507. static void
  508. drtx_tfirst(hp)
  509. struct drchan *hp;
  510. {
  511.     register int16 base = hp->base;
  512.     char c;
  513.     
  514.     /* Copy data to a local buffer to save on mbuf overheads
  515.      * during transmit interrupt time.
  516.      */
  517.     hp->drtx_cnt = len_p(hp->sndbuf);
  518.     hp->drtx_tcp = hp->drtx_buffer;
  519.     
  520.     pullup(&hp->sndbuf, hp->drtx_tcp, hp->drtx_cnt);
  521.     
  522.     /* Transmit the first character in the buffer */
  523.     c = *hp->drtx_tcp++;
  524.     hp->drtx_cnt--;
  525.  
  526.     write_scc(base, R0, RES_Tx_CRC);    /* Reset CRC */
  527.     write_scc(base, R0, RES_EOM_L);        /* Reset underrun latch */
  528.     outportb(base+DATA, c);            /* Output first character */
  529.     write_scc(base, R15, TxUIE);        /* Allow underrun ints only */
  530.     write_scc(base, R1, TxINT_ENAB|EXT_INT_ENAB); /* Tx/Ext status ints on */
  531.     write_scc(base, R9, MIE|NV);        /* master enable */
  532.     hp->tstate = ACTIVE;
  533.     hp->tx_state = drtx_active;
  534. }
  535.  
  536. /* drtx_active
  537.  * Transmit ACTIVE state processor
  538.  */
  539. static void
  540. drtx_active(hp)
  541. struct drchan *hp;
  542. {
  543.     if(hp->drtx_cnt-- > 0){
  544.         /* Send next character */
  545.         outportb(hp->base+DATA, *hp->drtx_tcp++);
  546.     } else {
  547.         /* No more to send - wait for underrun to hit */
  548.         hp->tstate = UNDERRUN;
  549.         hp->tx_state = drtx_flagout;
  550.         free_p(hp->sndbuf);
  551.         write_scc(hp->base, R0, RES_EOM_L);  /* Send CRC on underrun */
  552.         write_scc(hp->base, R0, RES_Tx_P);   /* Reset Tx Int pending */
  553.     }
  554. }
  555.  
  556. /* drtx_flagout
  557.  * Transmit FLAGOUT state processor
  558.  */
  559. static void
  560. drtx_flagout(hp)
  561. struct drchan *hp;
  562. {
  563.     /* Arrive here after CRC sent and Tx interrupt fires.
  564.      * Post a wake for ENDDELAY
  565.      */
  566.  
  567.     hp->tstate = UNDERRUN;
  568.     hp->tx_state = drtx_downtx;
  569.     write_scc(hp->base, R9, 0);
  570.     write_scc(hp->base, R0,  RES_Tx_P);
  571.     dr_wake(hp, TX, tx_fsm, hp->enddelay);
  572. }
  573.  
  574. /* drtx_downtx
  575.  * Transmit DOWNTX state processor
  576.  */
  577. static void
  578. drtx_downtx(hp)
  579. struct drchan *hp;
  580. {
  581.     register int base = hp->base;
  582.  
  583.     /* See if theres anything left to send - if there is,  send it ! */
  584.     if((hp->sndbuf = dequeue(&hp->sndq)) == NULLBUF){
  585.         /* Nothing left to send - return to receive */
  586.         write_scc(base, R5, Tx8|DTR);   /* Tx off now */
  587.         write_scc(base, R0, ERR_RES);   /* Reset error bits */
  588.         hp->tstate = IDLE;
  589.         hp->tx_state = drtx_idle;
  590.         hp->rstate = ENABLE;
  591.         hp->rx_state = drrx_enable;
  592.         drrx_enable(hp);
  593.     } else
  594.         drtx_tfirst(hp);
  595.  
  596. }
  597.     
  598. /* Write CTC register */
  599. static void
  600. write_ctc(port, reg, val)
  601. unsigned port,reg,val;
  602. {
  603.     char i_state;
  604.     int16 base = port;
  605.     
  606.     i_state = disable ();
  607.     /* Select register */
  608.     outportb(base+Z8536_MASTER,(char)reg);
  609.     outportb(base+Z8536_MASTER,(char)val);
  610.     restore(i_state);
  611. }
  612.  
  613. /* Read CTC register */
  614. static char
  615. read_ctc(port, reg)
  616. unsigned port, reg;
  617. {
  618.     char c,i_state;
  619.     int16 i,base = port;
  620.     
  621.     i_state = disable ();
  622.     /* Select register */
  623.         outportb(base+Z8536_MASTER,(char)(reg&0xFF));
  624.     /* Delay for a short time to allow 8536 to settle */
  625.     for(i=0;i<100;i++);
  626.     c = inportb(base+Z8536_MASTER);
  627.     restore(i_state);
  628.     return(c&0xFF);
  629. }
  630.  
  631. /* Initialize dr controller parameters */
  632. static int
  633. drchanparam(hp)
  634. register struct drchan *hp;
  635. {
  636.     int16 tc;
  637.     long br;
  638.     char i_state;
  639.     register int16 base;
  640.  
  641.     /* Initialize 8530 channel for SDLC operation */
  642.     base = hp->base;
  643.     i_state = disable ();
  644.  
  645.     switch(base & 2){
  646.     case 2:
  647.         write_scc(base,R9,CHRA);    /* Reset channel A */
  648.         break;
  649.     case 0:
  650.         write_scc(base,R9,CHRB);    /* Reset channel B */
  651.         break;
  652.     }
  653.     /* Deselect all Rx and Tx interrupts */
  654.     write_scc(base,R1,0);
  655.  
  656.     /* Turn off external interrupts (like CTS/CD) */
  657.     write_scc(base,R15,0);
  658.  
  659.     /* X1 clock, SDLC mode */
  660.     write_scc(base,R4,SDLC|X1CLK);     /* SDLC mode and X1 clock */
  661.  
  662.     /* Now some misc Tx/Rx parameters */
  663.     /* CRC PRESET 1, NRZI Mode */
  664.     write_scc(base,R10,CRCPS|NRZI);
  665.  
  666.     /* Set up BRG and DPLL multiplexers */
  667.     /* Tx Clk from RTxC. Rcv Clk from DPLL, TRxC pin outputs BRG */
  668.     write_scc(base,R11,RCDPLL|TCRTxCP|TRxCOI|TRxCBR);
  669.  
  670.     /* Null out SDLC start address */
  671.     write_scc(base,R6,0);
  672.  
  673.     /* SDLC flag */
  674.     write_scc(base,R7,FLAG);
  675.  
  676.     /* Set up the Transmitter but don't enable it */
  677.     /*  DTR, 8 bit TX chars only - TX NOT ENABLED */
  678.     write_scc(base,R5,Tx8|DTR);
  679.  
  680.     /* Receiver - initial setup only - more later */
  681.     write_scc(base,R3,Rx8);         /* 8 bits/char */
  682.  
  683.     /* Setting up BRG now - turn it off first */
  684.     write_scc(base,R14,BRSRC);     /* BRG off, but keep Pclk source */
  685.  
  686.     /* set the 32x time constant for the BRG */
  687.  
  688.     br = hp->speed;            /* get desired speed */
  689.     tc = ((XTAL/32)/br)-2;        /* calc 32X BRG divisor */
  690.  
  691.     write_scc(base,R12,tc&0xFF);      /* lower byte */
  692.     write_scc(base,R13,(tc>>8)&0xFF); /* upper bite */
  693.  
  694.     /* Time to set up clock control register for RECEIVE mode
  695.      * DRSI has xtal osc going to pclk at 4.9152 Mhz
  696.      * The BRG is sourced from that, and set to 32x clock
  697.      * The DPLL is sourced from the BRG.  BRG is fed to the TRxC pin
  698.      * Transmit clock is provided by the BRG externally divided by
  699.      * 32 in the CTC counter 1 and 2.
  700.      * Receive clock is from the DPLL
  701.      */
  702.  
  703.     /* Following subroutine sets up and ENABLES the receiver */
  704.     drrx_enable(hp);
  705.     
  706.     /* DPLL from BRG, BRG source is PCLK */
  707.     write_scc(hp->base,R14,BRSRC|SSBR);
  708.     /* SEARCH mode, keep BRG source */
  709.     write_scc(hp->base,R14,BRSRC|SEARCH);
  710.     /* Enable the BRG */
  711.     write_scc(hp->base,R14,BRSRC|BRENABL);
  712.  
  713.     /* enable the receive interrupts */
  714.  
  715.     write_scc(hp->base,R1,(INT_ALL_Rx|EXT_INT_ENAB));
  716.     write_scc(hp->base,R15,BRKIE);    /* ABORT int */
  717.     write_scc(hp->base,R9,MIE|NV);    /* master enable */
  718.  
  719.  
  720.     /* Now, turn on the receiver and hunt for a flag */
  721.     write_scc(hp->base,R3,RxENABLE|RxCRC_ENAB|Rx8);
  722.  
  723.     restore(i_state);
  724.     return 0;
  725. }
  726.  
  727. /*
  728.  * Initialize the CTC (8536)
  729.  * Only the counter/timers are used - the IO ports are un-comitted.
  730.  * Channels 1 and 2 are linked to provide a /32 counter to convert
  731.  * the SIO BRG to a real clock for Transmit clocking.
  732.  * CTC 3 is left free running on a 10 mS period.  It is always polled
  733.  * and therefore all interrupts from the chip are disabled.
  734.  *
  735.  * Updated 02/16/89 by N6TTO
  736.  * Changed to support the use of the second channel on the 8530.
  737.  * Added so that the driver works on the DRSI type 2 PC Adaptor
  738.  * which has 2 1200 bps modems.
  739.  *
  740.  */
  741. static void
  742. drinitctc(port)
  743. unsigned port;
  744. {
  745.     long i;
  746.  
  747.     /* Initialize 8536 CTC */
  748.  
  749.     /* Initialize 8536 */
  750.     /* Start by forcing chip into known state */
  751.     (void) read_ctc(port, Z8536_MICR);
  752.  
  753.     write_ctc(port, Z8536_MICR, 0x01);    /* Reset the CTC */
  754.     for(i=0;i < 1000L; i++)        /* Loop to delay */
  755.         ;
  756.     write_ctc(port, Z8536_MICR, 0x00);    /* Clear reset and start init seq. */
  757.  
  758.     /* Wait for chip to come ready */
  759.     while((read_ctc(port, Z8536_MICR)) != (char) 0x02)
  760.         ;
  761.  
  762.     write_ctc(port, Z8536_MICR, 0xa6);    /* MIE|NV|CT_VIS|RJA */
  763.     write_ctc(port, Z8536_MCCR, 0xf4);    /* PBE|CT1E|CT2E|CT3E|PAE */
  764.  
  765.     write_ctc(port, Z8536_CTMS1, 0xe2);    /* Continuous,EOE,ECE, Pulse output */
  766.     write_ctc(port, Z8536_CTMS2, 0xe2);    /* Continuous,EOE,ECE, Pulse output */
  767.     write_ctc(port, Z8536_CTMS3, 0x80);    /* Continuous,Pulse output */
  768.     write_ctc(port, Z8536_CT1MSB, 0x00);    /* Load time constant CTC #1 */
  769.     write_ctc(port, Z8536_CT1LSB, 0x10);
  770.     write_ctc(port, Z8536_CT2MSB, 0x00);    /* Load time constant CTC #2 */
  771.     write_ctc(port, Z8536_CT2LSB, 0x10);
  772.     write_ctc(port, Z8536_CT3MSB, 0x60);    /* Load time constant CTC #3 */
  773.     write_ctc(port, Z8536_CT3LSB, 0x00);
  774.  
  775.     write_ctc(port, Z8536_IVR, 0x06);
  776.  
  777.     /* Set port direction bits in port A and B
  778.      * Data is input on bits d1 and d5, output on d0 and d4.
  779.      * The direction is set by 1 for input and 0 for output
  780.      */
  781.     write_ctc(port, Z8536_PDCA, 0x22);
  782.     write_ctc(port, Z8536_PDCB, 0x22);
  783.  
  784.     write_ctc(port, Z8536_CSR1, Z_GCB|Z_TCB);  /* Start CTC #1 running */
  785.     write_ctc(port, Z8536_CSR2, Z_GCB|Z_TCB);  /* Start CTC #2 running */
  786.     write_ctc(port, Z8536_CSR3, Z_IE|Z_GCB|Z_TCB); /* Start CTC #3 running */
  787. }
  788.  
  789. /* Attach a DRSI interface to the system
  790.  * argv[0]: hardware type, must be "drsi"
  791.  * argv[1]: I/O address, e.g., "0x300"
  792.  * argv[2]: vector, e.g., "2"
  793.  * argv[3]: mode, must be "ax25"
  794.  * argv[4]: iface label, e.g., "dr0"
  795.  * argv[5]: receiver packet buffer size in bytes
  796.  * argv[6]: maximum transmission unit, bytes
  797.  * argv[7]: iface speed for channel A
  798.  * argv[8]: iface speed for channel B (defaults to same as A if absent)
  799.  * argv[9]: First IP address, optional (defaults to Ip_addr)
  800.  * argv[10]: Second IP address, optional (defaults to Ip_addr)
  801.  */
  802. int
  803. dr_attach(argc,argv,p)
  804. int argc;
  805. char *argv[];
  806. void *p;
  807. {
  808.     register struct iface *if_pca,*if_pcb;
  809.     struct drchan *hp;
  810.     int dev;
  811.     char *cp;
  812.  
  813.     /* Quick check to make sure args are good and mycall is set */
  814.     if(strcmp(argv[3],"ax25") != 0){
  815.         printf("Mode %s unknown for interface %s\n",
  816.             argv[3],argv[4]);
  817.         return -1;
  818.     }
  819.     if(if_lookup(argv[4]) != NULLIF){
  820.         printf(Existingiface, argv[4]);
  821.         return -1;
  822.     }    
  823.     if(Mycall[0] == '\0'){
  824.         printf("set mycall first\n");
  825.         return -1;
  826.     }
  827.     /* Note: More than one card can be supported if you give up a COM:
  828.      * port, thus freeing up an IRQ line and port address
  829.      */
  830.     if(Drnbr >= DRMAX){
  831.         printf("Only %d DRSI controller(s) supported right now!\n",DRMAX);
  832.         return -1;
  833.     }
  834.     dev = Drnbr++;
  835.  
  836.     /* Initialize hardware-level control structure */
  837.     Drsi[dev].addr = htoi(argv[1]);
  838.     Drsi[dev].vec = htoi(argv[2]);
  839.  
  840.     /* Save original interrupt vector */
  841.     Drsi[dev].oldvec = getirq(Drsi[dev].vec);
  842.  
  843.     /* Set new interrupt vector */
  844.     if(setirq(Drsi[dev].vec,Drhandle[dev]) == -1){
  845.         printf("IRQ %u out of range\n",Drsi[dev].vec);
  846.         Drnbr--;
  847.     }    
  848.     /* Initialize the CTC */
  849.     drinitctc(Drsi[dev].addr);
  850.     
  851.     /* Create iface structures and fill in details */
  852.     if_pca = (struct iface *)callocw(1,sizeof(struct iface));
  853.     if_pcb = (struct iface *)callocw(1,sizeof(struct iface));
  854.  
  855.     if_pca->addr = if_pcb->addr = Ip_addr;
  856.     if(argc > 9)
  857.         if_pca->addr = resolve(argv[9]);
  858.     if(argc > 10)
  859.         if_pcb->addr = resolve(argv[10]);
  860.     if(if_pca->addr == 0 || if_pcb->addr == 0){
  861.         tputs(Noipaddr);
  862.         free((char *)if_pca);
  863.         free((char *)if_pcb);
  864.         return -1;
  865.     }
  866.     /* Append "a" to iface associated with A channel */
  867.     cp = mallocw((unsigned)strlen(argv[4])+2);
  868.     strcpy(cp,argv[4]);
  869.     strcat(cp,"a");
  870.     if_pca->name = cp;
  871.  
  872.     /* Append "b" to iface associated with B channel */
  873.     cp = mallocw((unsigned)strlen(argv[4])+2);
  874.     strcpy(cp,argv[4]);
  875.     strcat(cp,"b");
  876.     if_pcb->name = cp;
  877.  
  878.     if_pcb->mtu = if_pca->mtu = atoi(argv[6]);
  879.     if_pcb->type = if_pca->type = CL_AX25;
  880.     if_pcb->ioctl = if_pca->ioctl = dr_ctl;
  881.     if_pca->dev = 2*dev;            /* dr0a */
  882.     if_pcb->dev = 2*dev + 1;        /* dr0b */
  883.     if_pcb->stop = if_pca->stop = dr_stop;
  884.     if_pcb->output = if_pca->output = ax_output;
  885.     if_pcb->raw = if_pca->raw = dr_raw;
  886.  
  887.     if_pca->iface_metric = if_pcb->iface_metric = 1;
  888.  
  889.     if(strcmp(argv[3],"ax25") == 0){
  890.         /* Must be true, was checked at top */
  891.         if_pcb->send = if_pca->send = ax_send;
  892.         if(if_pcb->hwaddr == NULLCHAR)
  893.             if_pcb->hwaddr = mallocw(sizeof(Mycall));
  894.         memcpy(if_pcb->hwaddr,(char *)&Mycall,sizeof(Mycall));
  895.         if(if_pcb->ipcall == NULLCHAR)
  896.             if_pcb->ipcall = mallocw(sizeof(Mycall));
  897.         memcpy(if_pcb->ipcall,(char *)&Mycall,sizeof(Mycall));
  898.         if(if_pca->hwaddr == NULLCHAR)
  899.             if_pca->hwaddr = mallocw(sizeof(Mycall));
  900.         memcpy(if_pca->hwaddr,(char *)&Mycall,sizeof(Mycall));
  901.         if(if_pca->ipcall == NULLCHAR)
  902.             if_pca->ipcall = mallocw(sizeof(Mycall));
  903.         memcpy(if_pca->ipcall,(char *)&Mycall,sizeof(Mycall));
  904.     }
  905.     /* Link em in to the iface chain */
  906.     if_pca->next = if_pcb;
  907.     if_pcb->next = Ifaces;
  908.     Ifaces = if_pca;
  909.  
  910.     /* set params in drchan table for CHANNEL B */
  911.  
  912.     hp = &Drchan[2*dev+1];                /* dr1 is offset 1 */
  913.     hp->iface = if_pcb;
  914.     hp->stata = Drsi[dev].addr + CHANA + CTL;    /* permanent status */
  915.     hp->statb = Drsi[dev].addr + CHANB + CTL;    /* addrs for CHANA/B*/
  916.     if(argc > 8){
  917.         /* Separate speed for channel B */
  918.         hp->speed = (int16)atoi(argv[8]);
  919.     } else {
  920.         /* Set speed to same as for channel A */
  921.         hp->speed = (int16)atoi(argv[7]);
  922.     }
  923.     hp->base = Drsi[dev].addr + CHANB;
  924.     hp->bufsiz = atoi(argv[5]);
  925.     hp->drtx_buffer = mallocw(if_pcb->mtu+100);
  926.     hp->tstate = IDLE;
  927.     hp->tx_state = drtx_idle;
  928.     hp->w[RX].wcall = NULL;
  929.     hp->w[RX].wakecnt = 0;
  930.     hp->w[TX].wcall = NULL;
  931.     hp->w[TX].wakecnt = 0;
  932.     /* default KISS Params */
  933.     hp->txdelay = 25;        /* 250 Ms */
  934.     hp->persist = 64;        /* 25% persistence */
  935.     hp->slotime = 10;        /* 100 Ms */
  936.     hp->squeldelay = 20;        /* 200 Ms */
  937.     hp->enddelay = 10;        /* 100 Ms */
  938.     
  939.     write_scc(hp->stata,R9,FHWRES);        /* Hardware reset */
  940.     
  941.     /* Disable interrupts with Master interrupt ctrl reg */
  942.     write_scc(hp->stata,R9,0);
  943.  
  944.     drchanparam(hp); 
  945.  
  946.     /* Initialize buffer pointers */
  947.     hp->rcvbuf = NULLBUF;
  948.     hp->rcvbuf->cnt = 0;
  949.     hp->sndq = NULLBUF;
  950.     
  951.     /* set params in drchan table for CHANNEL A */
  952.     hp = &Drchan[2*dev];            /* dr0a is offset 0 */
  953.     hp->iface = if_pca;
  954.     hp->speed = (int16)atoi(argv[7]);
  955.     hp->base = Drsi[dev].addr + CHANA;
  956.     hp->bufsiz = atoi(argv[5]);
  957.     hp->drtx_buffer = mallocw(if_pca->mtu+100);
  958.     hp->tstate = IDLE;
  959.     hp->tx_state = drtx_idle;
  960.     hp->w[RX].wcall = NULL;
  961.     hp->w[RX].wakecnt = 0;
  962.     hp->w[TX].wcall = NULL;
  963.     hp->w[TX].wakecnt = 0;
  964.     /* default KISS Params */
  965.     hp->txdelay = 30;        /* 300 Ms */
  966.     hp->persist = 64;        /* 25% persistence */
  967.     hp->slotime = 10;        /* 100 Ms */
  968.     hp->squeldelay = 20;        /* 200 Ms */
  969.     hp->enddelay = 10;        /* 100 Ms */
  970.  
  971.     drchanparam(hp);
  972.  
  973.     /* Initialize buffer pointers */
  974.     hp->rcvbuf = NULLBUF;
  975.     hp->rcvbuf->cnt = 0;
  976.     hp->sndq = NULLBUF;
  977.  
  978.     write_scc(hp->base,R9,MIE|NV);        /* master interrupt enable */
  979.  
  980.     /* Enable interrupt in 8259 interrupt controller */
  981.     maskon(Drsi[dev].vec);
  982.     
  983.     return 0;
  984. }
  985.  
  986. /* Shut down iface */
  987. static int
  988. dr_stop(iface)
  989. struct iface *iface;
  990. {
  991.     int16 dev;
  992.  
  993.     dev = iface->dev;
  994.     if(dev & 1)
  995.         return 0;
  996.     dev >>= 1;    /* Convert back into DRSI number */
  997.  
  998.     /* Set 8259 interrupt mask (turn off interrupts) */
  999.     maskoff(Drsi[dev].vec);
  1000.  
  1001.     /* Restore original interrupt vector */
  1002.     setirq(Drsi[dev].vec, Drsi[dev].oldvec);
  1003.     Drnbr--;
  1004.     
  1005.     /* Force hardware reset */
  1006.     write_scc(Drsi[dev].addr + CHANA + CTL,R9,FHWRES);
  1007.     /* Reset the CTC */
  1008.     (void) read_ctc(Drsi[dev].addr, Z8536_MICR);
  1009.     write_ctc(Drsi[dev].addr, Z8536_MICR, 0x01);
  1010.     return 0;
  1011. }
  1012.  
  1013. /* Send raw packet on DRSI card */
  1014. static int
  1015. dr_raw(iface,bp)
  1016. struct iface *iface;
  1017. struct mbuf *bp;
  1018. {
  1019.     char kickflag;
  1020.     struct drchan *hp;
  1021.     char i_st = disable ();
  1022.     
  1023.     dump(iface,IF_TRACE_OUT,CL_AX25,bp);
  1024.     iface->rawsndcnt++;
  1025.     iface->lastsent = secclock();
  1026.     hp = &Drchan[iface->dev];
  1027.     kickflag = (hp->sndq == NULL) & (hp->sndbuf == NULLBUF);
  1028.     /* clever! flag=1 if something in queue */
  1029.     enqueue(&hp->sndq,bp);
  1030.  
  1031.     if(kickflag)            /* simulate interrupt to xmit */
  1032.         tx_fsm(hp);        /* process interrupt */
  1033.  
  1034.     restore(i_st);
  1035.     return 0;
  1036. }
  1037.  
  1038. /* display DRSI Channel stats */
  1039. int
  1040. dodrstat(argc,argv,p)
  1041. int argc;
  1042. char *argv[];
  1043. void *p;
  1044. {
  1045.     struct drchan *hp0, *hp1;
  1046.     int i;
  1047.  
  1048.     for(i=0; i<DRMAX; i++){
  1049.         hp0 = &Drchan[i];
  1050.         hp1 = &Drchan[i+1];
  1051.         i = Drchan[i].base;
  1052.         tputs("DRSI Board Statistics - N6TTO 112790.0\n");
  1053.         tputs("--------------------------------------\n");
  1054.         tprintf("Channel - %s\n", hp0->iface->name);
  1055.         tprintf("Rxints  - %8ld  Txints  - %8ld  Exints  - %8ld\n",
  1056.             hp0->rxints, hp0->txints, hp0->exints);
  1057.         tprintf("Enqued  - %8ld  Crcerr  - %8ld  Aborts  - %8ld\n",
  1058.             hp0->enqueued, hp0->crcerr, hp0->aborts);
  1059.         tprintf("RFrames - %8ld  Rxovers - %8ld  TooBig  - %8ld\n",
  1060.             hp0->rxframes, hp0->rovers, hp0->toobig);
  1061.         tprintf("Txdefer - %8ld  Txppers - %8ld  Nomem   - %8ld\n",
  1062.             hp0->txdefers, hp0->txppersist, hp0->nomem);
  1063.         tprintf("Tx state  %8d  Rx state  %8d\n\n",hp0->tstate,hp0->rstate);
  1064.         tprintf("Channel - %s\n", hp1->iface->name);
  1065.         tprintf("Rxints  - %8ld  Txints  - %8ld  Exints  - %8ld\n",
  1066.             hp1->rxints, hp1->txints, hp1->exints);
  1067.         tprintf("Enqued  - %8ld  Crcerr  - %8ld  Aborts  - %8ld\n",
  1068.             hp1->enqueued, hp1->crcerr, hp1->aborts);
  1069.         tprintf("RFrames - %8ld  Rxovers - %8ld  TooBig  - %8ld\n",
  1070.             hp1->rxframes, hp1->rovers, hp1->toobig);
  1071.         tprintf("Txdefer - %8ld  Txppers - %8ld  Nomem   - %8ld\n",
  1072.             hp1->txdefers, hp1->txppersist, hp1->nomem);
  1073.         tprintf("Tx state  %8d  Rx state  %8d\n",hp1->tstate,hp1->rstate);
  1074.     }
  1075.     return 0;
  1076. }
  1077.  
  1078. /* Subroutine to set kiss params in channel tables */
  1079. static int32
  1080. dr_ctl(iface,cmd,set,val)
  1081. struct iface *iface;
  1082. int cmd;
  1083. int set;
  1084. int32 val;
  1085. {
  1086.     struct drchan *hp;
  1087.     hp = &Drchan[iface->dev];
  1088.  
  1089.     switch(cmd){
  1090.     case PARAM_TXDELAY:
  1091.         if(set)
  1092.             hp->txdelay = val;
  1093.         return hp->txdelay;
  1094.     case PARAM_PERSIST:
  1095.         if(set)
  1096.             hp->persist = val;
  1097.         return hp->persist;
  1098.     case PARAM_SLOTTIME:
  1099.         if(set)
  1100.             hp->slotime = val;
  1101.         return hp->slotime;
  1102.     case PARAM_TXTAIL:
  1103.         if(set)
  1104.             hp->squeldelay = val;
  1105.         return hp->squeldelay;
  1106.     case PARAM_ENDDELAY:
  1107.         if(set)
  1108.             hp->enddelay = val;
  1109.         return hp->enddelay;
  1110.     case PARAM_SPEED:
  1111.         return hp->speed;
  1112.     }
  1113.     return -1;
  1114. }
  1115.  
  1116. #endif /* DRSI */
  1117. #endif /* MSDOS */
  1118.